<template>
  <view class="tn-verification-code-input">
    <input
      class="code-input__input"
      :disabled="disabledKeyboard"
      :value="codeValue"
      type="number"
      :focus="focus"
      :maxlength="maxlength"
      :cursor-spacing="10"
      @input="handleInput"
    >
    <view
      v-for="(item, index) in maxlength"
      :key="item"
      class="code-input__item"
      :class="[itemClass(index)]"
      :style="itemStyle(index)"
    >
      <!-- 内容 -->
      <text :class="{'dot-text': dotFill && index < codeArray.length}">
        {{ index < codeArray.length ? (dotFill ? '●' : codeArray[index]) : '' }}
      </text>
      <!-- placeholder -->
      <view v-if="mode !== 'middleLine'" class="placeholder" :style="placeholderStyle(index)"></view>
      <!-- middleLine -->
      <view v-if="mode === 'middleLine'" class="middle-line" :style="lineStyle(index)"></view>
      <!-- bottomLine -->
      <view v-if="mode === 'bottomLine'" class="bottom-line" :style="lineStyle(index)"></view>
    </view>
  </view>
</template>

<script lang="ts" setup>
import { verificationCodeInputProps, verificationCodeInputEmits } from '../../../types/tn-verification-code-input'
import { ref, computed, CSSProperties, watch } from 'vue'
import { handleValueWithUnit, hump2str } from '../../../utils'
import { UPDATE_MODEL_EVENT } from '../../../constants'

const props = defineProps(verificationCodeInputProps)
const emits = defineEmits(verificationCodeInputEmits)


// item样式
const itemStyle = computed<(index: number) => CSSProperties>(() => {
  return (index: number) => {
    let style: CSSProperties = {}
    if (props?.fontSize) {
      style.fontSize = handleValueWithUnit(props.fontSize)
      style.width = handleValueWithUnit(props.fontSize)
      style.height = `calc(${style.width} + 10rpx)`
    }
    if (index < codeArray.value.length) {
      if (props.activeColor) {
        style.color = props.activeColor
        style.borderColor = props.activeColor
      }
    } else {
      if (props.inactiveColor) {
        style.color = props.inactiveColor
        style.borderColor = props.inactiveColor
      }
    }
    return style
  }
})
// placeholder样式
const placeholderStyle = computed<(index: number) => CSSProperties>(() => {
  return (index: number) => {
    let style: CSSProperties = {}
    style.display = index === codeArray.value.length ? 'block' : 'none'
    if (props.inactiveColor) {
      style.backgroundColor = props.inactiveColor
    }
    return style
  }
})
// line样式
const lineStyle = computed<(index: number) => CSSProperties>(() => {
  return (index: number) => {
    let style: CSSProperties = {}
    if (index < codeArray.value.length) {
      if (props.activeColor) {
        style.backgroundColor = props.activeColor
      }
    } else {
      if (props.inactiveColor) {
        style.backgroundColor = props.inactiveColor
      }
    }
    return style
  }
})

// item对应的类
const itemClass = computed<(index: number) => string>(() => {
  return (index: number) => {
    let clazz: string[] = []
    clazz.push(`code-input--${hump2str(props.mode, '-')}`)
    if (props.bold) clazz.push('tn-text-bold bold')
    if (index === codeArray.value.length) clazz.push('active')
    if (index < codeArray.value.length) clazz.push('input')
    return clazz.join(' ')
  }
})

// 验证码的值
let codeValue = ref<string>('')
watch(() => props.modelValue, (val: string | number) => {
  if (typeof val === 'number') codeValue.value = String(val)
  else codeValue.value = val
}, {
  immediate: true
})
// 验证码数组
const codeArray = computed<string[]>(() => {
  return codeValue.value.split('')
})

// 处理input的输入
const handleInput = (e: any) => {
  const value = e.detail.value
  if(value.length > props.maxlength) return
  emits(UPDATE_MODEL_EVENT, value)
  emits('change', value)
  if (value.length === props.maxlength) emits('complete', value)
}
</script>

<script lang="ts">
export default {
  options: {
    // 在微信小程序中将组件节点渲染为虚拟节点，更加接近Vue组件的表现(不会出现shadow节点下再去创建元素)
    virtualHost: true
  }
}
</script>

<style lang="scss" scoped>
@import '../../../theme.scss';

.tn-verification-code-input {
  text-align: center;
  position: relative;
  width: 100%;
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  justify-content: center;
  overflow: hidden;

  .code-input {
    &__input {
      position: absolute;
      top: 0;
      left: -100%;
      right: 200%;
      height: 100%;
      width: 300%;
      text-align: left;
      z-index: 10;
      background: none;
      opacity: 0;
    }

    &__item {
      position: relative;
      font-size: 60rpx;
      line-height: 1;
      width: 60rpx;
      height: calc(60rpx + 10rpx);
      margin-left: 16rpx;
      display: flex;
      align-items: center;
      justify-content: center;
      &:first-child {
        margin-left: 0rpx;
      }

      &.active {
        animation: breathe 2s infinite ease;
        .middle-line {
          background-color: $tn-main-color;
        }
      }
      &.input {
        color: $tn-main-color;
        .middle-line {
          display: none;
        }
        .bottom-line {
          background-color: $tn-main-color;
        }
        &.code-input--box {
          border-color: $tn-main-color;
        }
      }

      .placeholder {
        position: absolute;
        top: 50%;
        left: 50%;
        width: 4rpx;
        height: 70%;
        transform: translate(-50%, -50%);
        background-color: $tn-main-color;
        border-radius: 4rpx;
      }

      .middle-line, .bottom-line {
        position: absolute;
        width: 100%;
        height: 4rpx;
        background-color: #AAAAAA;
        border-radius: 4rpx;
      }
      .middle-line {
        top: 50%;
        transform: translateY(-50%);
      }
      .bottom-line {
        bottom: 0;
        left: 0;
        right: 0;
      }

      .dot-text {
        transform-origin: center center;
        transform: scale(0.6);
      }
    }

    /* 输入框样式 start */
    &--box {
      border: 2rpx solid #AAAAAA;
    }
    /* 输入框样式 end */
  }
}

@keyframes breathe {
  0% {
    opacity: 0.3;
  }
  50% {
    opacity: 1;
  }
  100% {
    opacity: 0.3;
  }
}
</style>
